﻿using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace GemTowerDefence
{
  public class Wave
  {
    private readonly List<Enemy> _enemies = new List<Enemy>(); // List of enemies
    private readonly Texture2D _enemyTexture; // A texture for the enemies
    private readonly int _numOfEnemies; // Number of enemies to spawn
    private readonly TileMap _tileMap; // A reference of the level
    private readonly int _waveNumber; // What wave is this?
    private readonly Texture2D _healthTexture;

    private int _enemiesSpawned; // How mant enemies have spawned

    private float _spawnTimer; // When should we spawn an enemy
    private bool _spawningEnemies; // Are we still spawing enemies?

    public Wave(int waveNumber, int numOfEnemies, Player player, TileMap tileMap, 
      Texture2D enemyTexture, Texture2D healthTexture)
    {
      Player = player;
      _waveNumber = waveNumber;
      _numOfEnemies = numOfEnemies;

      _tileMap = tileMap;
      _enemyTexture = enemyTexture;
      _healthTexture = healthTexture;
    }

    public Player Player { get; private set; }

    public bool RoundOver
    {
      get { return _enemies.Count == 0 && _enemiesSpawned == _numOfEnemies; }
    }

    public int RoundNumber
    {
      get { return _waveNumber; }
    }

    public bool EnemyAtEnd { get; set; }

    public bool IsStarted { get; set; }

    public List<Enemy> Enemies
    {
      get { return _enemies; }
    }

    private const float EnemySpeed = 2.5f;

    private void AddEnemy()
    {
      var waypoints = _tileMap.Waypoints;
      if (waypoints.Count == 0) return;

      var enemy = new Enemy(_enemyTexture, waypoints.Peek(), 50 + RoundNumber * 3, 1, EnemySpeed);

      enemy.SetWaypoints(waypoints);

      _enemies.Add(enemy);

      _spawnTimer = 0;
      _enemiesSpawned++;
    }

    public void Start()
    {
      IsStarted = true;
      _spawningEnemies = true;
    }

    public void Update(GameTime gameTime)
    {
      if (_enemiesSpawned == _numOfEnemies)
        _spawningEnemies = false; // We have spawned enough enemies

      if (_spawningEnemies)
      {
        _spawnTimer += (float) gameTime.ElapsedGameTime.TotalSeconds;

        if (_spawnTimer > EnemySpeed / 5.0)
          AddEnemy(); // Time to add a new enemey
      }

      for (int i = 0; i < _enemies.Count; i++)
      {
        Enemy enemy = _enemies[i];
        enemy.Update(gameTime);

        if (enemy.IsDead)
        {
          if (enemy.CurrentHealth > 0) // Enemy is at the end
          {
            EnemyAtEnd = true;
            Player.Lives -= 1;
          }
          else
          {
            Player.Money += enemy.BountyGiven;
          }

          _enemies.Remove(enemy);
          i--;
        }
      }
    }

    public void Draw(SpriteBatch spriteBatch)
    {
      foreach (Enemy enemy in _enemies)
      {
        enemy.Draw(spriteBatch);
        if (enemy.IsDead) continue;

        // Draw the health bar normally.
        var healthRectangle = new Rectangle((int)enemy.Position.X,
                                                  (int)enemy.Position.Y,
                                                  _healthTexture.Width,
                                                  _healthTexture.Height);

        spriteBatch.Draw(_healthTexture, healthRectangle, Color.Gray);

        float healthPercentage = enemy.HealthPercentage;
        float visibleWidth = _healthTexture.Width * healthPercentage;

        healthRectangle = new Rectangle((int)enemy.Position.X,
                                        (int)enemy.Position.Y,
                                        (int)(visibleWidth),
                                        _healthTexture.Height);

        spriteBatch.Draw(_healthTexture, healthRectangle, GetHealthBarColor(enemy.HealthPercentage));
      }
    }

    public Color GetHealthBarColor(float health)
    {
      int red = (health < 0.5 ? 255 : 255 - (int)((2 * health - 1) * 255));
      int green = (health > 0.5 ? 255 : (int)((2 * health) * 255));
      return new Color(red, green, 0);
    }

  }
}